package haha.life.normal;


import com.alibaba.fastjson.JSONObject;
import haha.life.common.SysTool;
import jzqb.po.QBBKPo;
import jzqb.po.QBBKTemplatePo;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.lang.reflect.Field;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;


public class FileUtil {

    /**
     * 通过文件路径读取 json文件
     *
     * @param fileName 文件名
     * @return
     */
    public static String readJsonFile(String fileName) {
        String jsonStr = "";
        InputStream inputStream = FileUtil.class.getClassLoader().getResourceAsStream("static/" + fileName);

        try (Reader reader = new InputStreamReader(inputStream, "utf-8")) {
            int ch = 0;
            StringBuffer sb = new StringBuffer();
            while ((ch = reader.read()) != -1) {
                sb.append((char) ch);
            }
            jsonStr = sb.toString();
            return jsonStr;
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 从流中读取json文件
     *
     * @param inputStream 输入流
     * @return
     */
    public static String readJsonFileFromStream(InputStream inputStream) {
        String jsonStr = "";
        try {
            Reader reader = new InputStreamReader(inputStream, "utf-8");
            int ch = 0;
            StringBuffer sb = new StringBuffer();
            while ((ch = reader.read()) != -1) {
                sb.append((char) ch);
            }
            reader.close();
            jsonStr = sb.toString();
            return jsonStr;
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * MultipartFile 转 File
     *
     * @param file
     * @throws Exception
     */
    public static File multipartFileToFile(MultipartFile file) throws Exception {

        File toFile = null;
        if (file.equals("") || file.getSize() <= 0) {
            file = null;
        } else {
            InputStream ins = null;
            ins = file.getInputStream();
            toFile = new File(file.getOriginalFilename());
            inputStreamToFile(ins, toFile);
            ins.close();
        }
        return toFile;
    }

    //获取流文件
    private static void inputStreamToFile(InputStream ins, File file) {
        try {
            OutputStream os = new FileOutputStream(file);
            int bytesRead = 0;
            byte[] buffer = new byte[8192];
            while ((bytesRead = ins.read(buffer, 0, 8192)) != -1) {
                os.write(buffer, 0, bytesRead);
            }
            os.close();
            ins.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 文件转为二进制数组
     * @param absolutePath 绝对路径
     * @return
     */
    public static byte[] fileToBinArray(String absolutePath){
        try {
            File file = new File(absolutePath);
            InputStream fis = new FileInputStream(file);
            byte[] bytes = FileCopyUtils.copyToByteArray(fis);
            return bytes;
        }catch (Exception ex){
            throw new RuntimeException("transform file into bin Array 出错",ex);
        }
    }

    /**
     * 删除本地临时文件
     *
     * @param file
     */
    public static void delteTempFile(File file) {
        if (file != null) {
            File del = new File(file.toURI());
            del.delete();
        }
    }

    /**
     * 保存文件
     * @param file
     * @param filePath 文件完整路径
     * @param fileName 文件名
     * @throws Exception
     */
    public static void saveFile(MultipartFile file, String filePath, String fileName) throws Exception {
        File targetFile = new File(filePath);
        if (!targetFile.exists()) {
            targetFile.mkdirs();
        }
        file.transferTo(new File(filePath, fileName));
    }

    /**
     * 删除文件或文件夹
     *
     * @param sPath
     * @return
     */
    public static boolean deleteFolder(String sPath) {
        boolean flag = false;
        File file = new File(sPath);
        // 判断目录或文件是否存在
        if (!file.exists()) {  // 不存在返回 false
            return flag;
        } else {
            // 判断是否为文件
            if (file.isFile()) {  // 为文件时调用删除文件方法
                return deleteFile(sPath);
            } else {  // 为目录时调用删除目录方法
                return deleteDirectory(sPath);
            }
        }
    }

    /**
     * 删除单个文件
     *
     * @param sPath 被删除文件的文件名
     * @return 单个文件删除成功返回true，否则返回false
     */
    public static boolean deleteFile(String sPath) {
        boolean flag = false;
        File file = new File(sPath);
        // 路径为文件且不为空则进行删除
        if (file.isFile() && file.exists()) {
            file.delete();
            flag = true;
        }
        return flag;
    }

    /**
     * 删除目录（文件夹）以及目录下的文件
     *
     * @param sPath 被删除目录的文件路径
     * @return 目录删除成功返回true，否则返回false
     */
    public static boolean deleteDirectory(String sPath) {
        //如果sPath不以文件分隔符结尾，自动添加文件分隔符
        if (!sPath.endsWith(File.separator)) {
            sPath = sPath + File.separator;
        }
        File dirFile = new File(sPath);
        //如果dir对应的文件不存在，或者不是一个目录，则退出
        if (!dirFile.exists() || !dirFile.isDirectory()) {
            return false;
        }
        boolean flag = true;
        //删除文件夹下的所有文件(包括子目录)
        File[] files = dirFile.listFiles();
        for (int i = 0; i < files.length; i++) {
            //删除子文件
            if (files[i].isFile()) {
                flag = deleteFile(files[i].getAbsolutePath());
                if (!flag) break;
            } //删除子目录
            else {
                flag = deleteDirectory(files[i].getAbsolutePath());
                if (!flag) break;
            }
        }
        if (!flag) return false;
        //删除当前目录
        if (dirFile.delete()) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 转换文件的编码
     *
     * @param absPath 源文件的绝对路径
     * @param old     旧的编码
     * @param New     新的编码
     */
    public static void transFileEncode(String absPath, String old, String New) throws IOException {
        //1.创建InputStreamReader对象，构造方法中传递字节输入流和指定的编码表名称GBK
        InputStreamReader isr = new InputStreamReader(new FileInputStream(absPath), old);
        //2.创建OutputTreamWrite对象，构造方法中传递字节输出流和指定的编码表名称UTF-8
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(absPath + "_tmp"), New);
        //3.使用InputStreamReader对象中的方法read读取文件
        int len = 0;
        while ((len = isr.read()) != -1) {
            //4.使用OutputTreamWrite对象中的方法write，把读取的数据写入到文件中
            osw.write(len);
        }
        //5.释放资源
        osw.close();
        isr.close();

    }

    /**
     * 从绝对路径读取文件,并写入结果流中
     *
     * @param os       输出流
     * @param zipos    压缩流
     * @param abspath  绝对路径
     * @param zipLevel 压缩包层级
     * @throws Exception 文件不存在
     */
    public static void writeStreamFromAbspath(DataOutputStream os, ZipOutputStream zipos, String abspath, String zipLevel) throws Exception {
        //判断文件是否存在
        File file = new File(abspath);
        if (file.exists()) {
            try {
                zipos.putNextEntry(new ZipEntry(zipLevel));
            } catch (Exception e) {
                System.out.println(zipLevel + "路径已存在");
                throw new Exception("路径已存在异常");
            }
//            zipos.putNextEntry(new ZipEntry(zipLevel));
            InputStream is = new FileInputStream(file);
            byte[] b = new byte[100];
            int length = 0;
            while ((length = is.read(b)) != -1) {
                os.write(b, 0, length);
            }
            is.close();
        } else {
            System.out.println("不存在:" + file.toString());
            throw new Exception("文件不存在异常");
        }
        zipos.closeEntry();
    }


    public static void zipFile(File file, String relativePath, ZipOutputStream zos) {
        InputStream is = null;
        try {
            if (!file.isDirectory()) {
                ZipEntry zp = new ZipEntry(relativePath);
                zos.putNextEntry(zp);
                is = new FileInputStream(file);
                byte[] buffer = new byte[1024];
                int length = 0;
                while ((length = is.read(buffer)) >= 0) {
                    zos.write(buffer, 0, length);
                }
//                zos.setEncoding("gbk");//解决文件名中文乱码
                zos.flush();
                zos.closeEntry();
            } else {
                String tempPath = null;
                for (File f : file.listFiles()) {
                    tempPath = relativePath + f.getName();
                    if (f.isDirectory()) {
                        tempPath += File.separator;
                    }
                    zipFile(f, tempPath, zos);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (is != null) {
                    is.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 生成情报百科REC文件(分为新建和编辑)
     *
     * @param type:add,edit
     * @param qbbkPo:前端模型
     * @return REC字符串
     */
    public static String generateQBBKRecFile(String type, QBBKPo qbbkPo) throws UnsupportedEncodingException {
//        String tempFileName = qbbkPo.getDigitFileName();
//        if (!"".equals(tempFileName) && tempFileName != null && tempFileName != "") {
//            qbbkPo.setDigitFileName(tempFileName.split("\\\\")[1]);
//        }
        String jsonStr = FileUtil.readJsonFile("qbbk.json");
        JSONObject jsonObject = JSONObject.parseObject(jsonStr);

        //定义返回结果
        String RECfile = "";

        //String nowStr = RandomUtils.nowStr("");
        String nowStr = SysTool.getCurrentTime(SysTool.dateFormat_date);
        if ("add".equals(type)) {
            RECfile = "<REC>";
            //编辑时间
            RECfile = RECfile + "<编辑时间>=" + nowStr;
            //记录添加时间
            RECfile = RECfile + "<SYS_FLD_RECORDADDDATE>=" + nowStr;
            //新建时,更新时间默认等于新建时间
            RECfile = RECfile + "<SYS_FLD_RECORDUPDATEDATE>=" + nowStr;
        } else if ("edit".equals(type)) {
            RECfile = "<REC>" + "<SYS_FLD_SYSID>=" + qbbkPo.getSysID();
            //编辑时间
            RECfile = RECfile + "<编辑时间>=" + nowStr;
            //记录数据更新时间
            RECfile = RECfile + "<SYS_FLD_RECORDUPDATEDATE>=" + nowStr;
        }

        //记录文件的更新时间
//        if (qbbkPo.getDigitFileName() != "") {
//            RECfile = RECfile + "<SYS_FLD_FILEUPDATEDATE>=" + nowStr;
//        }

        //遍历前端对象,重映射key
        Field[] fields = qbbkPo.getClass().getDeclaredFields();
        for (int i = 0, len = fields.length; i < len; i++) {
            // 对于每个属性，获取属性名
            String varName = fields[i].getName();
            try {
                // 获取原来的访问控制权限
                boolean accessFlag = fields[i].isAccessible();
                // 修改访问控制权限
                fields[i].setAccessible(true);
                // 获取在对象f中属性fields[i]对应的对象中的变量
                Object o;
                try {
                    o = fields[i].get(qbbkPo);
                    try {
                        varName = jsonObject.get(varName).toString();
                        RECfile += String.format("<%s>=%s", varName, o);
                    } catch (NullPointerException e) {
                        continue;
                    }
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
                // 恢复访问控制权限
                fields[i].setAccessible(accessFlag);
            } catch (IllegalArgumentException ex) {
                ex.printStackTrace();
            }
        }
//        qbbkPo.setDigitFileName(tempFileName);
        String finalRECfile=RECfile.replaceAll("null", "");
        return finalRECfile;
    }

    /**
     * 生成情报百科模板REC文件(分为新建和编辑)
     *
     * @param type:add,edit
     * @param qbbkTemplatePo:前端模型
     * @return REC字符串
     */
    public static String generateQBBKTemplateREC(String type,QBBKTemplatePo qbbkTemplatePo) throws UnsupportedEncodingException {
        String jsonStr = FileUtil.readJsonFile("qbbkmb.json");
        JSONObject jsonObject = JSONObject.parseObject(jsonStr);
        //定义返回结果
        String RECfile = "";

        String nowStr = SysTool.getCurrentTime(SysTool.dateFormat_milli);
        if ("add".equals(type)) {
            RECfile = "<REC>";
            //记录创建时间
            RECfile = RECfile + "<创建时间>=" + nowStr;
            //新建时,更新时间默认等于新建时间
            RECfile = RECfile + "<修改时间>=" + nowStr;
        } else if ("edit".equals(type)) {
            RECfile = "<REC>" + "<ID>=" + qbbkTemplatePo.getId();
            //记录数据更新时间
            RECfile = RECfile + "<修改时间>=" + nowStr;
        }

        //遍历前端对象,重映射key
        Field[] fields = qbbkTemplatePo.getClass().getDeclaredFields();
        for (int i = 0, len = fields.length; i < len; i++) {
            // 对于每个属性，获取属性名
            String varName = fields[i].getName();
            try {
                // 获取原来的访问控制权限
                boolean accessFlag = fields[i].isAccessible();
                // 修改访问控制权限
                fields[i].setAccessible(true);
                // 获取在对象f中属性fields[i]对应的对象中的变量
                Object o;
                try {
                    o = fields[i].get(qbbkTemplatePo);
                    try {
                        varName = jsonObject.get(varName).toString();
                        RECfile += String.format("<%s>=%s", varName, o);
                    } catch (NullPointerException e) {
                        continue;
                    }
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
                // 恢复访问控制权限
                fields[i].setAccessible(accessFlag);
            } catch (IllegalArgumentException ex) {
                ex.printStackTrace();
            }
        }
//        qbbkPo.setDigitFileName(tempFileName);
        String finalRECfile=RECfile.replaceAll("null", "");
        return finalRECfile;
    }

    /**
     * 计算抽象路径
     * @param fileName   文件名
     * @param dbBasePath 数据库字段存放地址
     * @return
     */
    public static String calculateAbstractPath( String fileName,String dbBasePath){
        String dirName = RandomUtils.getDirByName(fileName);
        String tmpPath = new File(dbBasePath,dirName).toString();
        String dbAbsPath = new File(tmpPath,fileName).toString();
        return dbAbsPath;
    }




}
